// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2004-11-6

#include "stdafx.h"
#include "net_sockdata.h"

namespace JoyServer
{

CJoySockData::CJoySockData()
{
    m_owner         = NULL;
    m_handle        = NULL;
    m_closeTime     = 0;
    m_closeTimeout  = 30000;
    m_bStream       = true;
    m_bRecv         = true;
}

CJoySockData::~CJoySockData()
{
    if(m_handle != INVALID_SOCKET)
    {
        ::shutdown(m_handle, SD_BOTH);
        ::closesocket(m_handle);
    }
}

// class CJoyReleaseSockData

CJoyReleaseSockData::CJoyReleaseSockData()
{
    m_event = NULL;
    m_thread= NULL;
    m_stop  = false;
}

CJoyReleaseSockData::~CJoyReleaseSockData()
{
}

DWORD WINAPI CJoyReleaseSockData::sReleaseProc(void* p)
{
    return ((CJoyReleaseSockData*)p)->ReleaseProc();
}

DWORD WINAPI CJoyReleaseSockData::ReleaseProc()
{
    while(!m_stop)
    {
        WaitForSingleObject(m_event, INFINITE);

        ReleaseDatas();
    }
    return 0;
}

CJoySockData* CJoyReleaseSockData::PeekData()
{
    CJoyAutoCS gate(m_lock);
    if(m_datas.IsEmpty())
    {
        ResetEvent(m_event);
        return NULL;
    }
    return m_datas.RemoveHead();
}

void CJoyReleaseSockData::PostData(CJoySockData* pData)
{
    CJoyAutoCS gate(m_lock);

    BOOL bEmpty = m_datas.IsEmpty();
    m_datas.AddTail(pData);
    pData->AddRef();
    pData->m_closeTime  = GetTickCount();

    if(bEmpty)
    {
        SetEvent(m_event);
    }
}

void CJoyReleaseSockData::ReleaseDatas()
{
    CJoySockData* data = PeekData();
    while(data != NULL)
    {
        bool shouldRelease = true;
        // if timeout or nothing to send, we should release the data.
        if(data->m_sendCount > 0 && data->m_closeTimeout > 0)
        {
            DWORD dwTick = GetTickCount();
            if(dwTick-data->m_closeTime < data->m_closeTimeout)
            {
                shouldRelease = false;
            }            
        }
        if(shouldRelease)
        {
            ::shutdown(data->m_handle, SD_BOTH);
            ::closesocket(data->m_handle);
            TRACE("send count %d; time %d; err %d",
                data->m_sendCount, GetTickCount()-data->m_closeTime);
            data->m_handle = INVALID_SOCKET;
            data->Release();
        }
        else
        {
            BOOL bEmpty;
            {
                CJoyAutoCS gate(m_lock);
                bEmpty = m_datas.IsEmpty();
                m_datas.AddTail(data);
            }
            if(bEmpty)
            {
                // only wait for the current data.
                // so we should wait a short time.
                Sleep(100);
            }
        }

        data = PeekData();
    }
}

void CJoyReleaseSockData::Init()
{
    m_event  = CreateEvent(NULL, TRUE, FALSE, NULL);
    DWORD dwThreadId = 0;
    m_thread = CreateThread(NULL, 0, sReleaseProc, this, 0, &dwThreadId);
}

void CJoyReleaseSockData::Free()
{
    m_stop = true;
    SetEvent(m_event);
    WaitForSingleObject(m_thread, INFINITE);
    CloseHandle(m_thread);
    CloseHandle(m_event);

    m_thread = NULL;
    m_event  = NULL;
}


} // namespace JoyServer